package mh.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;

/**
 * Manage all kind of SHA hashing is needed by the program.
 * 
 * @author Gianmarco Laggia
 * @since 0.2
 * 
 */
public class SHAHash {

	/**
	 * Takes the input and calculate the SHA-256 hash.
	 * 
	 * @param in
	 *            The string to convert
	 * @return The SHA-256 Hash
	 * @throws NoSuchAlgorithmException
	 *             In case the algoritm is not found
	 */
	public static String digest(String in) throws NoSuchAlgorithmException {

		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(in.getBytes());

		byte byteData[] = md.digest();

		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < byteData.length; i++) {
			String hex = Integer.toHexString(0xff & byteData[i]);
			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}
		return hexString.toString();
	}

	/**
	 * Takes the input and calculate the SHA-256 hash.
	 * 
	 * @param in
	 *            The char array to convert
	 * @return The SHA-256 Hash
	 * @throws NoSuchAlgorithmException
	 *             In case the algoritm is not found
	 */
	public static String digest(char[] in) throws NoSuchAlgorithmException {

		MessageDigest md = MessageDigest.getInstance("SHA-256");

		ArrayList<Byte> list = new ArrayList<Byte>();
		for (int i = 0; i < in.length; i++) {
			String ch = String.valueOf(in[i]);
			byte[] b = ch.getBytes();
			for (int j = 0; j < b.length; j++) {
				list.add(b[j]);
			}
		}
		byte[] inputInByte = new byte[list.size()];
		for (int i = 0; i < list.size(); i++) {
			inputInByte[i] = list.get(i);
		}
		md.update(inputInByte);

		byte byteData[] = md.digest();

		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < byteData.length; i++) {
			String hex = Integer.toHexString(0xff & byteData[i]);
			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}
		return hexString.toString();
	}

	/**
	 * Takes the input, prefixs it with the salt and calculate the SHA-256 hash.
	 * 
	 * @param salt
	 *            The salt to be added
	 * @param password
	 *            The char array to convert
	 * @return The SHA-256 Hash
	 * @throws NoSuchAlgorithmException
	 *             In case the algoritm is not found
	 */
	public static String digestSalted(String salt, char[] password) throws NoSuchAlgorithmException {
		MessageDigest md = MessageDigest.getInstance("SHA-256");

		ArrayList<Byte> list = new ArrayList<Byte>();
		for (int i = 0; i < password.length; i++) {
			String ch = String.valueOf(password[i]);
			byte[] b = ch.getBytes();
			for (int j = 0; j < b.length; j++) {
				list.add(b[j]);
			}
		}
		byte[] saltInBytes = salt.getBytes();
		byte[] toBeHashed = new byte[(saltInBytes.length + list.size())];
		for (int i = 0; i < saltInBytes.length; i++) {
			toBeHashed[i] = saltInBytes[i];
		}
		for (int i = saltInBytes.length; i < (list.size() + saltInBytes.length); i++) {
			toBeHashed[i] = list.get(i - saltInBytes.length);
		}

		md.update(toBeHashed);

		byte byteData[] = md.digest();

		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < byteData.length; i++) {
			String hex = Integer.toHexString(0xff & byteData[i]);
			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
		}
		return hexString.toString();

	}

	/**
	 * Takes the input, prefixs it with the salt and calculate the SHA-256 hash.
	 * 
	 * @param salt
	 *            The salt to be added
	 * @param password
	 *            The string to convert
	 * @return The SHA-256 Hash
	 * @throws NoSuchAlgorithmException
	 *             In case the algoritm is not found
	 */
	public static String digestSalted(String salt, String password) throws NoSuchAlgorithmException {
		if ((salt == null) || (password == null)) {
			throw new NullPointerException();
		}
		return digest(salt + password);
	}
}
